/*
 * Powered By XY
 * Since 2020
 */

package com.xy.biz.rs.service.impl;

import com.xy.biz.rs.domain.bo.RecordTemplateBO;
import com.xy.biz.rs.domain.bo.RecordTemplateGroupBO;
import com.xy.biz.rs.domain.bo.RecordTemplateItemBO;
import com.xy.biz.rs.domain.converter.RecordTemplateGroupConverter;
import com.xy.biz.rs.domain.enums.RecordTemplateSequenceTypeEnum;
import com.xy.biz.rs.domain.query.RecordTemplateByIdQuery;
import com.xy.biz.rs.domain.query.RecordTemplateQuery;
import com.xy.biz.rs.domain.req.GetRecordTemplateGroupRequest;
import com.xy.biz.rs.domain.req.GetRecordTemplateRequest;
import com.xy.biz.rs.domain.req.UpdateRecordTemplateSequenceRequest;
import com.xy.biz.rs.domain.req.UpdateRecordTemplateStatusRequest;
import com.xy.biz.rs.domain.resp.GetRecordTemplateGroupResponse;
import com.xy.biz.rs.manager.RecordTemplateManager;
import com.xy.biz.rs.manager.RecordTemplateMinioManager;
import com.xy.biz.rs.service.RecordTemplateService;
import com.xy.lang.domain.Result;
import com.xy.lang.domain.tuples.Pair;
import com.xy.lang.enums.ApplyStatusEnum;
import com.xy.lang.enums.AuditStatusEnum;
import com.xy.lang.util.CollectionUtilsEx;
import com.xy.tool.context.UserContextHolder;
import com.xy.tool.gid.service.GidService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 *
 * @author zsp
 * @date 2022-1-4
 */
@Slf4j
@Service
public class RecordTemplateServiceImpl implements RecordTemplateService {

    @Autowired
    private GidService gidService;
    @Autowired
    private RecordTemplateManager recordTemplateManager;
    @Autowired
    private RecordTemplateMinioManager recordTemplateMinioManager;

    @Override
    public Result<?> saveRecordTemplate(RecordTemplateBO recordTemplateBO) {
        LocalDateTime now = LocalDateTime.now();
        if (Objects.isNull(recordTemplateBO.getStatus())) {
            recordTemplateBO.setStatus(ApplyStatusEnum.START.getCode());
        }
        recordTemplateBO.setAuditStatus(AuditStatusEnum.UNDO.getCode());
        recordTemplateBO.setTenantId(UserContextHolder.getTenantId());
        recordTemplateBO.setCreateTime(now);
        recordTemplateBO.setCreateUserId(UserContextHolder.getUserId());
        recordTemplateBO.setCreateUserName(UserContextHolder.getUserName());
        recordTemplateBO.setUpdateTime(now);
        recordTemplateBO.setUpdateUserId(UserContextHolder.getUserId());
        recordTemplateBO.setUpdateUserName(UserContextHolder.getUserName());
        int affectedRows = recordTemplateManager.saveRecordTemplate(recordTemplateBO);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> updateRecordTemplate(RecordTemplateBO recordTemplateBO) {
        RecordTemplateBO found
                = recordTemplateManager.getRecordTemplate(RecordTemplateByIdQuery.builder()
                .recordTemplateId(recordTemplateBO.getRecordTemplateId())
                .build());
        if (Objects.isNull(found)) {
            return Result.ofNotFound("输入了不存在的模板：" + recordTemplateBO.getRecordTemplateId());
        }

        found.setAuditStatus(AuditStatusEnum.UNDO.getCode());
        LocalDateTime now = LocalDateTime.now();
        found.setUpdateTime(now);
        found.setUpdateUserId(UserContextHolder.getUserId());
        found.setUpdateUserName(UserContextHolder.getUserName());
        int affectedRows = recordTemplateManager.updateRecordTemplate(found);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> deleteRecordTemplate(Long recordTemplateId) {
        int affectedRows = recordTemplateManager.deleteRecordTemplate(recordTemplateId);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public RecordTemplateBO getRecordTemplate(RecordTemplateByIdQuery request) {
        return recordTemplateManager.getRecordTemplate(request);
    }

    @Override
    public List<RecordTemplateBO> listRecordTemplate(RecordTemplateQuery query) {
        return recordTemplateManager.listRecordTemplate(query);
    }

    @Override
    public int countRecordTemplate(RecordTemplateQuery query) {
        return recordTemplateManager.countRecordTemplate(query);
    }

    @Override
    public Result<?> updateRecordTemplateForStatus(UpdateRecordTemplateStatusRequest request) {
        RecordTemplateBO found = recordTemplateManager.getRecordTemplate(RecordTemplateByIdQuery.builder()
                .recordTemplateId(request.getRecordTemplateId())
                .build());
        if (Objects.isNull(found)) {
            return Result.ofNotFound("输入了不存在的模板：" + request.getRecordTemplateId());
        }
        found.setStatus(request.getStatus());
        int affectedRows = recordTemplateManager.updateRecordTemplate(found);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> saveRecordTemplateGroup(RecordTemplateGroupBO recordTemplateGroupBO) {
        List<RecordTemplateGroupBO> recordTemplateGroupBOList = recordTemplateManager.listRecordTemplateGroupByTemplateId(recordTemplateGroupBO.getRecordTemplateId(), false);
        if (!CollectionUtils.isEmpty(recordTemplateGroupBOList)) {
            if (recordTemplateGroupBOList.stream()
                    .anyMatch(e -> Objects.equals(e.getSequence(), recordTemplateGroupBO.getSequence()))) {
                return Result.ofBadRequest("已存在相同排序号的数据！");
            }
        }
        recordTemplateGroupBO.setReferenceCount(1);
        recordTemplateGroupBO.setVersion(0L);
        recordTemplateGroupBO.setStatus(ApplyStatusEnum.START.getCode());
        recordTemplateGroupBO.setTenantId(UserContextHolder.getTenantId());
        int affectedRows = recordTemplateManager.saveRecordTemplateGroup(recordTemplateGroupBO);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> updateRecordTemplateGroup(RecordTemplateGroupBO recordTemplateGroupBO) {
        RecordTemplateGroupBO recordTemplateGroup =
                recordTemplateManager.getRecordTemplateGroup(recordTemplateGroupBO.getRecordTemplateGroupId(), false);
        if (Objects.isNull(recordTemplateGroup)) {
            return Result.ofNotFound("无此数据：" + recordTemplateGroupBO.getRecordTemplateGroupId());
        }
        List<RecordTemplateGroupBO> filterList = new ArrayList<>();
        if (Objects.nonNull(recordTemplateGroupBO.getStatus())) {
            List<RecordTemplateGroupBO> recordTemplateGroupBOList =
                    recordTemplateManager.listRecordTemplateGroupByTemplateId(recordTemplateGroup.getRecordTemplateId(), false);
            if (!Objects.equals(ApplyStatusEnum.START.getCode(), recordTemplateGroup.getStatus())) {
                filterList = CollectionUtilsEx.quickSort(recordTemplateGroupBOList
                        , recordTemplateGroup.getSequence()
                        , RecordTemplateGroupBO::setSequence);
            } else {
                recordTemplateGroupBO.setSequence(
                        (recordTemplateGroupBOList.get((recordTemplateGroupBOList.size() - 1)).getSequence() + 1));
            }
        }
        filterList.add(recordTemplateGroupBO);
        int affectedRows = recordTemplateManager.updateAllRecordTemplateGroup(filterList);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> deleteRecordTemplateGroup(Long recordTemplateGroupId) {
        RecordTemplateGroupBO recordTemplateGroup =
                recordTemplateManager.getRecordTemplateGroup(recordTemplateGroupId, false);
        if (Objects.isNull(recordTemplateGroup)) {
            return Result.ofNotFound("无此数据：" + recordTemplateGroupId);
        }
        List<RecordTemplateGroupBO> recordTemplateGroupBOList =
                recordTemplateManager.listRecordTemplateGroupByTemplateId(recordTemplateGroup.getRecordTemplateId(), false);
        List<RecordTemplateGroupBO> filterList = CollectionUtilsEx.quickSort(recordTemplateGroupBOList
                , recordTemplateGroup.getSequence()
                , RecordTemplateGroupBO::setSequence);
        int affectedRows = recordTemplateManager.deleteRecordTemplateGroup(new Pair<>(recordTemplateGroupId, filterList));
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public List<RecordTemplateGroupBO> listRecordTemplateGroupByTemplateId(Long recordTemplateId, boolean withItem) {
        return recordTemplateManager.listRecordTemplateGroupByTemplateId(recordTemplateId, withItem);
    }

    @Override
    public Map<Long, List<GetRecordTemplateGroupResponse>> groupRecordTemplateGroupByTemplateId
            (List<Long> recordTemplateIdList, boolean withItem) {
        List<GetRecordTemplateGroupResponse> recordTemplateGroupBOList =
                RecordTemplateGroupConverter.toResponse(recordTemplateManager.groupRecordTemplateGroupByTemplateId(recordTemplateIdList, withItem));
        if (CollectionUtils.isEmpty(recordTemplateGroupBOList)) {
            return Collections.emptyMap();
        }
        return recordTemplateGroupBOList.stream().collect(Collectors.groupingBy(GetRecordTemplateGroupResponse::getRecordTemplateId));
    }

    @Override
    public Result<?> saveRecordTemplateItem(RecordTemplateItemBO recordTemplateItemBO) {
        recordTemplateItemBO.setVersion(0L);
        recordTemplateItemBO.setStatus(ApplyStatusEnum.START.getCode());
        recordTemplateItemBO.setTenantId(UserContextHolder.getTenantId());
        int affectedRows = recordTemplateManager.saveRecordTemplateItem(recordTemplateItemBO);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> copyRecordTemplate(GetRecordTemplateRequest request) {
        RecordTemplateBO recordTemplate = recordTemplateManager.getRecordTemplate(RecordTemplateByIdQuery.builder()
                .recordTemplateId(request.getRecordTemplateId())
                .withGroup(request.getWithGroup())
                .withItem(request.getWithItem())
                .build());
        if (Objects.isNull(recordTemplate)) {
            return Result.ofNotFound(String.valueOf(request.getRecordTemplateId()));
        }
        recordTemplate.restore();
        if (request.getWithGroup()) {
            List<RecordTemplateGroupBO> groupList = recordTemplate.getGroupList();
            copyGroup(groupList, request.getWithItem());
        }
        return saveRecordTemplate(recordTemplate);
    }

    @Override
    public Result<?> copyRecordTemplateGroup(GetRecordTemplateGroupRequest request) {
        RecordTemplateGroupBO recordTemplateGroup =
                recordTemplateManager.getRecordTemplateGroup(request.getRecordTemplateGroupId(), Objects.equals(true, request.getWithItem()));
        if (Objects.isNull(recordTemplateGroup)) {
            return Result.ofNotFound(String.valueOf(request.getRecordTemplateGroupId()));
        }
        List<RecordTemplateGroupBO> recordTemplateGroupBOList = recordTemplateManager.listRecordTemplateGroupByTemplateId(recordTemplateGroup.getRecordTemplateId(), false).stream()
                .sorted((e1, e2) -> e2.getSequence().compareTo(e1.getSequence()))
                .collect(Collectors.toList());
        Long recordTemplateId = recordTemplateGroup.getRecordTemplateId();
        copyGroup(Collections.singletonList(recordTemplateGroup), request.getWithItem());
        Integer lastSequence = recordTemplateGroupBOList.get(0).getSequence();
        recordTemplateGroup.setRecordTemplateId((recordTemplateId));
        recordTemplateGroup.setSequence(1 + lastSequence);
        int row = recordTemplateManager.saveRecordTemplateGroup(recordTemplateGroup);
        if (row > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    private void copyGroup(List<RecordTemplateGroupBO> groupList, boolean withItem) {
        if (!CollectionUtils.isEmpty(groupList)) {
            groupList.forEach(e -> {
                e.restoreGroup();
                e.setRecordTemplateGroupId(gidService.generate());
                if (withItem) {
                    List<RecordTemplateItemBO> itemList = e.getItemList();
                    if (!CollectionUtils.isEmpty(itemList)) {
                        itemList.forEach(RecordTemplateItemBO::restoreItem);
                    }
                }
            });
        }
    }

    /**
     * 保存模板项图片
     *
     * @param request
     */
    @Override
    public Result<?> saveRecordTemplateItemPicture(MultipartHttpServletRequest request) {
        return recordTemplateMinioManager.upload(request);
    }

    @Override
    public Result<?> updateRecordTemplateItem(RecordTemplateItemBO recordTemplateItemBO) {
        RecordTemplateItemBO templateItemBO =
                recordTemplateManager.getRecordTemplateItem(recordTemplateItemBO.getRecordTemplateGroupId());
        if (Objects.isNull(templateItemBO)) {
            return Result.ofNotFound("无此数据：" + recordTemplateItemBO.getRecordTemplateGroupId());
        }
        List<RecordTemplateItemBO> filterList = new ArrayList<>();
        if (Objects.nonNull(recordTemplateItemBO.getStatus())) {
            List<RecordTemplateItemBO> recordTemplateItemBOList =
                    recordTemplateManager.listRecordTemplateItemByGroupId(templateItemBO.getRecordTemplateGroupId());
            if (!Objects.equals(ApplyStatusEnum.START.getCode(), templateItemBO.getStatus())) {
                filterList = CollectionUtilsEx.quickSort(recordTemplateItemBOList
                        , templateItemBO.getSequence()
                        , RecordTemplateItemBO::setSequence);
            } else {
                recordTemplateItemBO.setSequence(
                        (recordTemplateItemBOList.get((recordTemplateItemBOList.size() - 1)).getSequence() + 1));
            }
        }
        filterList.add(recordTemplateItemBO);

        int affectedRows = recordTemplateManager.updateAllRecordTemplateItem(filterList);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> deleteRecordTemplateItem(Long recordTemplateItemId) {

        RecordTemplateItemBO templateItemBO =
                recordTemplateManager.getRecordTemplateItem(recordTemplateItemId);
        if (Objects.isNull(templateItemBO)) {
            return Result.ofNotFound("无此数据：" + recordTemplateItemId);
        }
        List<RecordTemplateItemBO> recordTemplateItemBOList =
                recordTemplateManager.listRecordTemplateItemByGroupId(templateItemBO.getRecordTemplateGroupId());
        List<RecordTemplateItemBO> filterList = CollectionUtilsEx.quickSort(recordTemplateItemBOList
                , templateItemBO.getSequence()
                , RecordTemplateItemBO::setSequence);
        int affectedRows = recordTemplateManager.deleteRecordTemplateItem(new Pair<>(recordTemplateItemId, filterList));
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> updateRecordTemplateSequence(UpdateRecordTemplateSequenceRequest request) {
        int row = 0;
        if (Objects.equals(RecordTemplateSequenceTypeEnum.RECORD_TEMPLATE_GROUP.getCode(),
                request.getRecordTemplateSequenceType())) {
            List<RecordTemplateGroupBO> recordTemplateGroupBOList =
                    recordTemplateManager.listRecordTemplateGroupByTemplateId(request.getParentId(), false);
            if (CollectionUtils.isEmpty(recordTemplateGroupBOList)) {
                return Result.ofNotFound(String.valueOf(request.getParentId()));
            }
            List<RecordTemplateGroupBO> templateGroupBOList;
            try {
                templateGroupBOList = CollectionUtilsEx.swapSort(recordTemplateGroupBOList, request.getCheckedSequence(), request.getPreviousSequence()
                        , RecordTemplateGroupBO::getSequence, RecordTemplateGroupBO::setSequence);
            } catch (IllegalArgumentException e) {
                log.error(e.getMessage());
                return Result.ofBadRequest(e.getMessage());
            }
            if (!CollectionUtils.isEmpty(templateGroupBOList)) {
                row = recordTemplateManager.updateAllRecordTemplateGroup(templateGroupBOList);
            }
        } else if (Objects.equals(RecordTemplateSequenceTypeEnum.RECORD_TEMPLATE_ITEM.getCode(),
                request.getRecordTemplateSequenceType())) {
            List<RecordTemplateItemBO> recordTemplateItemBOList =
                    recordTemplateManager.listRecordTemplateItemByGroupId(request.getParentId());
            if (CollectionUtils.isEmpty(recordTemplateItemBOList)) {
                return Result.ofNotFound(String.valueOf(request.getParentId()));
            }
            List<RecordTemplateItemBO> templateItemBOList;
            try {
                templateItemBOList = CollectionUtilsEx.swapSort(recordTemplateItemBOList, request.getCheckedSequence(), request.getPreviousSequence()
                        , RecordTemplateItemBO::getSequence, RecordTemplateItemBO::setSequence);
            } catch (IllegalArgumentException e) {
                log.error(e.getMessage());
                return Result.ofBadRequest(e.getMessage());
            }
            if (!CollectionUtils.isEmpty(templateItemBOList)) {
                row = recordTemplateManager.updateAllRecordTemplateItem(templateItemBOList);
            }
        }
        if (row > 0) {
            return Result.success();
        }
        return Result.fail();
    }

}
